import { observer } from "./observer/index"
import { nextTick } from "./utils/nextTick"
import Watcher from "./observer/watcher"

export function initState (vm) {
  let opts = vm.$options

  if (opts.data) {
    initData(vm)
  }
  if (opts.watch) {
    initWatch(vm)
  }
  if (opts.props) {
    initProps(vm)
  }
  if (opts.computed) {
    initComputed(vm)
  }
  if (opts.methods) {
    initMethods(vm)
  }
}

// vue2 data属性初始化
function initData (vm) {
  let data = vm.$options.data;
  data = vm._data = typeof data === 'function' ? data.call(vm) : data;

  // 将data上的所有属性代理到示例上
  for(let key in data) {
    proxy(vm, '_data', key)
  }

  // 数据进行劫持
  observer(data);
}

function proxy (vm, source, key) {
  Object.defineProperty(vm, key, {
    get () {
      return vm[source][key];
    },
    set (newValue) {
      vm[source][key] = newValue;
    }
  })
}

function initProps () {}

function initComputed () {}

function initWatch (vm) {
  // 1、获取watch
  let watch = vm.$options.watch

  for (let key in watch) {
    // 获取属性对应的值
    // 判断
    // 可能是数组、对象、函数、字符
    let handler = watch[key];
    if (Array.isArray(handler)) {
      handler.forEach(item => {
        createWatcher(vm, key, item);
      })
    } else {
      // 创建一个方法来处理
      createWatcher(vm, key, handler);
    }
  }
}

// vm.$watch(() => {return 'a'}) // 返回的值就是 watcher 上的属性 user = false
// 格式化处理
function createWatcher (vm, expOrfn, handler, options) {
  // 处理handler
  if (typeof handler === 'object') {
    options = handler // 用户的配置项
    handler = handler.handler
  }
  if (typeof handler === 'string') {
    // 将实例上的方法作为handler
    // 方法的代理和data的代理是一样的
    handler = vm[handler]
  }

  // 其它的都是函数
  // watch最终处理 $watch 这个方法
  return vm.$watch(vm, expOrfn, handler, options)
}

function initMethods () {}

export function stateMixin (vm) {
  // 列队包含2个类型事件：1、vue本身的数据更新 2、用户自己操作的数据更新
  // nextTick: 数据更新之后获取到最新的DOM
  vm.prototype.$nextTick = function (cb) {
    nextTick(cb)
  }

  vm.prototype.$watch = function (vmObj, expOrfn, handler, options) {
    // console.log('1111111111111111111111111111111===', vmObj, expOrfn, handler, options)
    // 实现watch 方法 就是使用new Watcher
    // 渲染走 渲染watcher   $watch走的是Watcher  (user  false  标识)
    // watch 核心 Watcher
    let watcher = new Watcher(vmObj, expOrfn, handler, {...options, user: true})
    if (options.immediate) {
      // 如果有这个immediate  立即执行
      handler.call(vm)
    }
  }
}


// $nextTick 原理

// watch 基本使用 init